home *** CD-ROM | disk | FTP | other *** search
- /*
- * Copyright (C) 1985-1992 New York University
- *
- * This file is part of the Ada/Ed-C system. See the Ada/Ed README file for
- * warranty (none) and distribution info and also the GNU General Public
- * License for more details.
-
- */
-
- /* Avoid problems with library routines on PC that require pointer
- * to double instead of double (this is violation of ANSI specs).
- * for now do not compile these modules
- */
-
- /*
- * 11-oct-85 shields
- * fix so can handle most negative integer properly. The changes
- * are more in the nature of a patch than a solution. The proper
- * way is NOT to convert negative values to positive form before
- * processing; instead, positive values should be converted to
- * negative and conversions done on negative values. However, this
- * can be put off until later.
- *
- * 5-jun-85 shields
- * add rat_tol and int_tol which are like rat_toi and int_toi, resp.,
- * except that they return long results. These are needed to support
- * fixed-point in generator.
- *
- * 1-aug-85 shields
- * add calls to int_free() to free intermediate values known to be dead.
- * add some copies where needed in building new rational values.
- */
-
- #include <stdlib.h>
- #include <stdio.h>
- #include <ctype.h>
- #include <string.h>
- #include <math.h>
- #include "config.h"
- #include "miscprots.h"
-
- typedef struct Rational_s {
- int *rnum; /* numerator */
- int *rden; /* denominator */
- } Rational_s;
- typedef Rational_s * Rational;
-
- #include "arithprots.h"
-
- static int *int_frl(long);
- static int *int_ptn(int);
- static int *subu_int(int *, int *);
- static void int_div(int *, int *, int **, int **);
- static int *int__addu(int *, int *);
- static int *int__norm(int *);
- static int *int_new(int);
- static void int_free(int *);
- static void rat_free(Rational);
- static double pow2(int);
-
- /* Some of the procedures want to signal overflow by returning the
- * string 'OVERFLOW'. In C we do this by setting global arith_overflow
- * to non-zero if overflow occurs, zero otherwise
- */
- int arith_overflow = 0;
-
-
- int ADA_MIN_INTEGER;
- int ADA_MAX_INTEGER;
- int *ADA_MAX_INTEGER_MP;
- int *ADA_MIN_INTEGER_MP;
- long ADA_MIN_FIXED, ADA_MAX_FIXED;
- int *ADA_MIN_FIXED_MP, *ADA_MAX_FIXED_MP;
- /* _LONG form is form that can be held in C (long) */
- #ifdef MAX_INTEGER_LONG
- long MIN_INTEGER_LONG;
- int *MAX_INTEGER_LONG_MP;
- int *MIN_INTEGER_LONG_MP;
- #endif
-
- #define ABS(x) ((x)<0 ? -(x) : (x))
- #define SIGN(x) ((x)<0 ? -1 : (x) == 0 ? 0 : 1)
-
-
- /*
- * M U L T I P L E P R E C I S I O N I N T E G E R
- *
- * A R I T H M E T I C P A C K A G E
- *
- * Robert B. K. Dewar
- * June 16th, 1980
- *
- * This package of routines implements multiple precision integer
- * arithmetic using what are called the "classical algorithms" in
- * Knuth "Art of Programming", Volume 2, Section 4.3.1. The style
- * of the algorithms follows Knuth fairly closely, and section
- * 4.3.1 can be consulted for further theoretical details.
- *
- * Multiple precision integers are represented as tuples of small
- * integers in the range 0 to BAS - 1, where BAS is a power of 10
- *(actually 10 ** DIGS) which is the base used to represent the
- * long integers. Essentially the successive elements of the tuple
- * are the digits of the representation in base BAS. All integers
- * are normalized so that the first digit is non-zero, except in
- * the case of zero itself. The sign is carried with the first
- * digit value, all remaining digits are always positive.
- *
- * Some examples of the representation, assuming DIGS = 4 and
- * BAS = 10000(note that the choice of BAS as a power of 10
- * is for convenience of the conversion routines, and is not
- * required for correct operation of the arithmetic algorithms).
-
- * -123456789 [-1 , 2345 , 6789]
- * 0 [0]
- * 123456789 [1 , 2345, 6789]
-
- * The constants BAS and DIGS must be defined as global constants
- * in a program using these routines. It is assumed that the value
- * BAS * BAS - 1 can be represented as a SETL integer value.
-
- * The following routines are provided:
-
- * int_abs integer absolute value
- * int_add integer addition
- * int_div integer division
- * int_eql integer equal to
- * int_exp raise multiple integer to multiple integer power
- * int_fri convert multiple precision integer from integer
- * int_frs convert multiple precision integer from string
- * int_geq integer greater than or equal to
- * int_gtr integer greater than
- * int_len number of digits in multiple precision integer
- * int_leq integer less than or equal to
- * int_lss integer less than
- * int_mod integer modulus
- * int_mul integer multiplication
- * int_neq integer not equal to
- * int_ptn integer power of ten
- * int_quo integer quotient
- * int_rem integer remainder
- * int_sub integer subtraction
- * int_toi convert integer to C integer
- * int_tos integer to string
- * int_umin integer unary minus
- */
-
- /* Internal procedures have names starting with int__ */
-
- int *int_abs(int *u) /*;int_abs*/
- {
- /* Absolute value of multiple precision integer */
- int *pu;
-
- pu = int_copy(u);
- if (pu[1] < 0)
- pu[1] = -pu[1];
- return pu;
- }
-
- int *int_add(int *u, int *v) /*;int_add*/
- {
- /* Add signed integers
- * This procedure implements the familiar algorithm of comparing
- * the signs, if the signs are the same, then the result is the
- * sum of the magnitudes with the sign of the operands. If the
- * signs differ, then the number with the smaller magnitude is
- * subtracted from the larger magnitude and the result sign is
- * that of the operand with the larger magnitude.
- */
-
- int *t;
-
- if (u[1] >= 0 && v[1] >= 0)
- return (int__addu(u, v));
- else
- if (u[1] < 0 && v[1] < 0) {
- u[1] = -u[1];
- v[1] = -v[1];
- t = int__addu(u, v);
- u[1] = -u[1];
- v[1] = -v[1];
- t[1] = -t[1];
- return t;
- }
- else {
- int us, vs;
- if (us = (u[1] < 0)) {
- u[1] = -u[1];
- }
- if (vs = (v[1] < 0)) {
- v[1] = -v[1];
- }
- if (int_gtr(u, v)) {
- t = subu_int(u, v);
- if (vs) v[1] = -v[1];
- if (us) {
- u[1] = -u[1];
- t[1] = -t[1];
- }
- return t;
- }
- else {
- t = subu_int(v, u);
- if (us) u[1] = -u[1];
- if (vs) {
- v[1] = -v[1];
- t[1] = -t[1];
- }
- return t;
- }
- }
- }
-
- int int_eql(int *u, int *v) /*;int_eql*/
- {
- /* Compare multiple precision integers for equality */
-
- int n;
-
- if (u[0] != v[0])
- return FALSE;
-
- for (n = u[0]; n > 0; n--)
- if (u[n] != v[n]) return FALSE;
- return TRUE;
- }
-
- int *int_exp(int *u, int *v) /*;int_exp*/
- {
- /* Raise a multiple precision integer to a multiple precision integer
- * power using a modified version of the Russian Peasant algorithm
- * for exponentiation.
- */
-
- int sn;
- int u1;
- int i;
- int carry;
- int half;
- int *running, *runningp;
- int *result, *resultp;
-
- /* Compute sign of result: positive if v is even, the sign of u if
- * v is odd.
- */
-
- sn =((v[v[0]] % 2) == 1) ? SIGN(u[1]) : 1;
- u1 = u[1];
- if (u[1] < 0)
- u[1] = -u1;
- v = int_copy(v);
-
- /* Starting the result at 1 and running at u, loop through the binary
- * digits of v, squaring running each time, and multiplying the result
- * by the current value of running each time a 1-bit is found.
- */
-
- result = int_con(1);
- running = int_copy(u);
-
- while(int_nez(v)) {
- /* If v is odd then multiply result by running. */
-
- if (v[v[0]] % 2 == 1) {
- resultp = result; /* save current value */
- result = int_mul(result, running);
- int_free(resultp); /* free dead value */
- }
-
- /* Square running. */
-
- runningp = running; /* save current value */
- running = int_mul(running, running);
- int_free(runningp); /* free dead value */
-
- /* Halve v. */
-
- carry = 0;
- for (i = 1; i <= v[0]; i++) {
- half = BAS * carry + v[i];
- carry = half % 2;
- v[i] = half / 2;
- }
- v = int__norm(v);
- }
-
- int_free(running);
- int_free(v);
-
- if (sn < 1)
- result[1] = -result[1];
- u[1] = u1;
- return result;
- }
-
- int *int_fri(int i) /*;int_fri*/
- {
- /* Convert an integer to a multiple precision integer.
- *
- * First check the sign of i.
- */
-
- int sn = 0;
- int n = i;
- int *t;
- int ti;
- int d;
-
- if (i < 0) {
- /* Special test for most negative as code below won't work
- * for this single value (on twos-complement machines)
- */
- if (i == ADA_MIN_INTEGER)
- return int_copy(ADA_MIN_INTEGER_MP);
- sn = -1;
- n = -i;
- }
- /* Determine length of result */
- d = 0;
- while(n) {
- d++;
- n /= BAS;
- }
- /* Now build up t in groups of BAS digits until i is depleted. */
-
- if (i < 0)
- i = -i;
- if (i > 0) {
- t = int_new(d);
- ti = t[0];
- while(i) {
- t[ti--] = i % BAS;
- i /= BAS;
- }
- }
- else
- t = int_con(0);
-
- if (sn < 0)
- t[1] = -t[1];
-
- return t;
- }
-
- #ifdef MAX_INTEGER_LONG
- /* variant of int_fri needed for PC only */
- static int *int_frl(long i) /*;int_frl*/
- {
- /* Convert a long integer to a multiple precision integer.
- *
- * First check the sign of i.
- */
-
- int sn = 0;
- long n = i;
- int *t;
- int ti;
- int d;
-
- if (i < 0) {
- /* Special test for most negative as code below won't work
- * for this single value (on twos-complement machines)
- */
- sn = -1;
- n = -i;
- }
- /* Determine length of result */
- d = 0;
- while(n) {
- d++;
- n /= BAS;
- }
- /* Now build up t in groups of BAS digits until i is depleted. */
-
- if (i < 0)
- i = -i;
- if (i > 0) {
- t = int_new(d);
- ti = t[0];
- while(i) {
- t[ti--] = i % BAS;
- i /= BAS;
- }
- }
- else
- t = int_con(0);
-
- if (sn < 0)
- t[1] = -t[1];
-
- return t;
- }
- #else
- /* if ints and longs same size, just use int_fri */
- static int *int_frl(long i) /*;int_frl*/
- {
- return int_fri((int)i);
- }
- #endif
-
- int *int_frs(char *s) /*;int_frs*/
- {
- /* Convert a string to multiple precision integer format. The string
- * s is a non-empty sequence of digits, possibly preceded by a sign
- *(+ or -).
- *
- * Erroneous strings are converted to OM.
- *
- * Since the base is a power of ten, the process of conversion
- * amounts simply to converting groups of DIGS digits.
- */
-
- char *t;
- int dg;
- int *r, len;
- int ri, z, sn;
- int n;
-
- if (*s == '+') {
- sn = 0;
- s++;
- }
- else
- if (*s == '-') {
- sn = -1;
- s++;
- }
- else
- sn = 0;
-
- /* now determine length */
- t = s;
- dg = 0;
- while(*t) {
- if (!isdigit(*t++))
- return (int *)0;
- dg++;
- }
- if (dg == 0)
- return (int *)0;
-
- z = dg % DIGS;
- r = int_new((dg / DIGS) +(z ? 1 : 0));
- ri = 1;
- len = z ? z : DIGS;
-
- while(dg > 0) {
- n = 0;
- dg -= len;
- while(len--) { /* convert next len digits */
- n = n * 10 +(*s++ - '0');
- }
- len = DIGS;
- r[ri++] = n;
- }
- if (sn < 0)
- r[1] = -r[1];
- return int__norm(r);
- }
-
- int int_geq(int *u, int *v) /*;int_geq*/
- {
- /* Compare multiple precision integers: return true if u >= v, false
- * otherwise.
- */
-
- return int_eql(u, v) || int_gtr(u, v);
- }
-
- int int_gtr(int *u, int *v) /*;int_gtr*/
- {
- /* Compare multiple precision integers: return true if u > v, false
- * otherwise.
- */
-
- int i, neg;
-
- /* signs are different */
-
- if (u[1] >= 0 && v[1] < 0) return TRUE;
-
- if (u[1] < 0 && v[1] >= 0) return FALSE;
-
- /* Now we have a real compare(signs the same) */
-
- neg = u[1] < 0; /* get the sign */
-
- if (u[0] > v[0]) return (neg ? FALSE : TRUE);
-
- if (u[0] < v[0]) return (neg ? TRUE : FALSE);
-
- /* Now the lengths are the same */
-
- if(u[1] != v[1]) return (u[1] > v[1]);
-
- /* Most significant digit is the same */
-
- for (i = 2; i <= u[0]; i++) {
- if (u[i] != v[i]) {
- return (neg ?(v[i] > u[i]) :(u[i] > v[i]));
- }
- }
-
- /* Numbers are the same */
-
- return FALSE;
- }
-
- /* Not used */
- int int_len(int *u) /*;int_len*/
- {
- /* Return the number of digits in a multiple precision integer. */
-
- int n = 1;
- int v;
-
- v = u[1];
- if (v < 0)
- v = -v; /* take absolute value */
- while(v) {
- n++;
- v /= 10;
- }
- return n +(u[0] - 1) * DIGS;
- }
-
- /* Not used */
- int int_leq(int *u, int *v) /*;int_leq*/
- {
- /* Compare multiple precision integers: return true if u <= v, false
- * otherwise.
- */
-
- return ! int_gtr(u, v);
- }
-
- int int_lss(int *u, int *v) /*;int_lss*/
- {
- /* Compare multiple precision integers: return true if u < v, false
- * otherwise.
- */
-
- return ! int_geq(u, v);
- }
-
- int *int_mod(int *u, int *v) /*;int_mod*/
- {
- /* Find u mod v where the mod operation is defined as:
- *
- * u mod v = u - v * N such that sign(u mod v) = sign v
- * and abs(u mod v) < abs v
- */
-
- int *r, *s;
-
- r = int_rem(u, v);
-
- if (r == (int *)0 || r[1] == 0 ||(SIGN(u[1]) == SIGN(v[1])))
- return r;
- else {
- s = int_add(r, v);
- int_free(r);
- return s;
- }
- }
-
- int *int_mul(int *u, int *v) /*;int_mul*/
- {
- /* Multiply signed integers, cf Knuth 4.3.1 Algorithm M
- *
- * Multiplication is similar to, but not identical with, the
- * usual pencil and paper algorithm. The main difference is
- * that the sum is accumulated as we go along, rather than
- * forming all the partial sums and adding them up at the end.
- *
- * First we acquire the sign of the result, and set each number
- * to its absolute value, thus the multiplication proper always
- * works with non-negative integers.
- */
-
- int sn;
- int u1;
- int v1;
- int *w;
- int i, j;
- int k;
- int t;
-
- sn = u[1] * v[1];
- u1 = u[1];
- v1 = v[1];
- if (u[1] < 0)
- u[1] = -u1;
- if (v[1] < 0)
- v[1] = -v1;
- /* Initialize result to all zeroes(actually it is only absolutely
- * necessary to initialize the last #v digits of w to zero).
- */
-
- w = int_new(u[0] + v[0]);
-
- /* Outer loop, through digits of multiplier */
-
- for (j = v[0]; j > 0; j--) {
- /* The inner loop, through the digits of the multiplicand, is
- * similar to the inner loop of the addition, except that the
- * product is added in, and the carry, k, can exceed 1.
- */
-
- k = 0;
- for (i = u[0]; i > 0; i--) {
- t = u[i] * v[j] + w[i + j] + k;
- w[i + j] = t % BAS;
- k = t / BAS;
- }
-
- /* The final step in the inner loop is to store the final
- * carry in the next position in the result.
- */
-
- w[j] = k;
- }
-
- /* The result must be normalized(there could be one leading zero),
- * and then the result sign attached to the returned value.
- */
-
- w = int__norm(w);
- /* Restore arguments to entry value */
- u[1] = u1;
- v[1] = v1;
- if (sn < 0)
- w[1] = -w[1];
- return w;
- }
-
- /* Not used */
- int int_neq(int *u, int *v) /*;int_neq*/
- {
- /* Compare multiple precision integers for inequality */
-
- return ! int_eql(u, v);
- }
-
- static int *int_ptn(int n) /*;int_ptn*/
- {
- /* Return the result 10**n as a multiple precision
- * integer, where n is a non-negative simple integer.
- */
-
- int d1;
- int *p;
- int i;
-
- d1 = 1;
- for (i = 1; i <= (n % DIGS); i++)
- d1 *= 10;
- p = int_new(1 +(n / DIGS));
- p[1] = d1;
- return p;
- }
-
- int *int_quo(int *u, int *v) /*;int_quo*/
- {
- /* Obtain quotient of dividing u by v */
-
- int *q, *r;
-
- if (int_eqz(v))
- return (int *)0;
- int_div(u, v, &q, &r);
- if(r != (int *)0) int_free(r); /* remainder not needed, free it */
- return q;
- }
-
- int *int_rem(int *u, int *v) /*;int_rem*/
- {
- /* Obtain remainder from dividing u by v, where u rem v is defined as:
- *
- * u rem v = u -(u/v) * v such that sign(u rem v) = sign u
- * and abs(u rem v) < abs v
- */
-
- int *q, *r;
-
- if (int_eqz(v))
- return (int *)0;
- int_div(u, v, &q, &r);
- if (q != (int *) 0) int_free(q); /* quotient not needed, free it */
- return r;
- }
-
- int *int_sub(int *u, int *v) /*;int_sub*/
- {
- /* Subtract signed integers
- *
- * There is no point in duplicating the int_add code, so we
- * simply negate the right argument and call the add routine!
- */
-
- int *w;
-
- v[1] = -v[1];
- w = int_add(u, v);
- v[1] = -v[1];
- return w;
- }
-
- int int_toi(int *t) /*;int_toi*/
- {
- /* Convert a multiple precision integer to a SETL integer, if possible.
- * Otherwise, return 'OVERFLOW'.
- *
- * First check if it overflows.
- */
-
- int sgn;
-
- int x;
- int i;
-
- arith_overflow = 0; /* reset overflow flag */
- sgn = SIGN(t[1]);
-
- if (sgn == 0)
- return 0;
- if (sgn > 0)
- t[1] = -t[1];
-
- /* the value of t must be in the interval */
- if (int_lss(t, ADA_MIN_INTEGER_MP)
- || int_gtr(t, ADA_MAX_INTEGER_MP)) {
- if (sgn > 0)
- t[1] = -t[1]; /* restore first component */
- arith_overflow = 1;
- return 0;
- }
-
- x = t[1]; /* set first part of result (must do here since negative) */
- for (i = 2; i <= t[0]; i++)
- x = BAS * x - t[i];
-
- if (sgn > 0) {
- t[1] = -t[1]; /* restore sign if negative */
- x = -x; /* and give result proper value */
- }
-
- return x;
- }
-
- #ifdef MAX_INTEGER_LONG
- long int_tol(int *t) /*;int_tol*/
- {
- /* Convert a multiple precision integer to a long integer, if possible.
- * Otherwise, return 'OVERFLOW'.
- *
- * First check if it overflows.
- */
-
- int sgn;
- long x;
- long res;
- int i;
-
- arith_overflow = 0; /* reset overflow flag */
- sgn = SIGN(t[1]);
-
- if (sgn == 0)
- return (long)0;
- if (sgn < 0) {
- #ifdef MAX_INTEGER_LONG
- if (int_eql(t, MIN_INTEGER_LONG_MP))
- return MIN_INTEGER_LONG;
- #else
- if (int_eql(t, ADA_MIN_INTEGER_MP))
- return ADA_MIN_INTEGER;
- #endif
-
- /* since not most negative, can change sign */
- t[1] = -t[1];
- }
-
- #ifdef MAX_INTEGER_LONG
- if (int_gtr(t, MAX_INTEGER_LONG_MP)) {
- arith_overflow = 1;
- return (long) 0;
- }
- #else
- if (int_gtr(t, ADA_MAX_INTEGER_MP)) {
- arith_overflow = 1;
- return (long) 0;
- }
- #endif
-
- x = 0;
- for (i = 1; i <= t[0]; i++)
- x = BAS * x + t[i];
-
- if (sgn < 0)
- t[1] = -t[1]; /* restore sign if negative */
-
- return (sgn * x);
- }
- #else
- /* if longs and ints are same size, no need for separate procedure */
- long int_tol(int *t) /*;int_tol*/
- {
- return (long) int_toi(t);
- }
- #endif
-
- char *int_tos(int *u) /*;int_tos*/
- {
- /* Convert a multiple precision integer to a string.
- * The string is a non-empty digit sequence with a possible leading
- * minus sign(but a plus sign is never generated).
- *
- * As in int_frs, the fact that the base is a power of ten means
- * that the conversion is simply a matter of converting successive
- * digits to decimal strings of length DIGS.
- */
-
- char *s, *t;
- int i, n;
- if (u == (int *)0) chaos("int_tos: arg null *");
-
- n = u[0] * DIGS;
- if (u[1] < 0)
- n += 1; /* if need minus sign */
- s = t = emalloct((unsigned) n + 1, "int-to-s");
- sprintf(s, "%d", u[1]);
- for (i = 2; i <= u[0]; i++) {
- while(*++s); /* move to end of converted string */
- sprintf(s, "%0*d", DIGS, u[i]);
- }
-
- return t;
- }
-
- int *int_umin(int *u) /*;int_umin*/
- {
- /* Unary minus on multiple precision integer. */
-
- u = int_copy(u);
- u[1] = -u[1];
- return u;
- }
-
- static int *subu_int(int *u, int *v) /*subu_int*/
- {
- /* Subtract unsigned integers, u >= v, cf Knuth 4.3.1 Algorithm S
- *
- *(note that we know as an entry condition that #u >= #v).
- */
-
- int ui, vi;
- int *w;
- int k; /* borrow */
-
- w = int_new(u[0]);
- ui = u[0];
- vi = v[0];
-
- /* The subtraction is similar to the addition, except that k now
- * represents the borrow condition and has values 0 or -1.
- */
-
- k = 0;
- while(vi) {
- w[ui] = u[ui] - v[vi--] + k;
- if (w[ui] < 0) {
- w[ui] += BAS;
- k = -1;
- }
- else
- k = 0;
- ui--;
- }
-
- /* Loop over remaining digits(if any) of u */
-
- while(ui) {
- w[ui] = u[ui] + k;
- if (w[ui] < 0) {
- w[ui] += BAS;
- k = -1;
- }
- else
- k = 0;
- ui--;
- }
-
- /* We cannot have a final borrow(since the entry condition
- * required that u >= v). However, we must normalize the
- * result since it is possible for leading zeroes to appear.
- */
-
- w = int__norm(w);
- return w;
- }
-
- static void int_div(int *u, int *v, int **qa, int **ra) /*;int_div*/
- {
- /* Obtain quotient and remainder of signed integers,
- * cf Knuth 4.3.1 Algorithm D
- * Result is returned as a tuple [quotient, remainder].
- *
- * This is by far the most difficult of the four basic operations.
- * This is because the paper and pencil algorithm involves certain
- * amounts of guess work which cannot be programmed directly. The
- * approach(which is analyzed in detail in Knuth) is to reduce
- * the guess work by computing a rather good guess at each digit
- * of the result, and then correcting if the guess is wrong.
- *
- * If the divisor is zero, return om.
- */
-
- int i, j, k, du, v1, p, c, d;
- int rr, rs;
- int *r, *q;
- int *t, *tt;
- int ti, n, m, qe, qs;
-
- if (int_eqz(v)) {
- *qa = (int *)0;
- *ra = (int *)0;
- return;
- }
-
- /* A special case, if u is shorter than v, the result is 0 */
-
- if (u[0] < v[0]) {
- *qa = int_con(0);
- *ra = int_copy(u);
- return;
- }
-
- /* Otherwise we initialize as in multiplication by obtaining the
- * result sign and then working with non-negative integers.
- */
-
- u = int_copy(u); /* arguments used destructively, so copy */
- v = int_copy(v);
- qs = u[1] * v[1];
- rs = u[1];
- v1 = v[1];
- if (rs < 0)
- u[1] = -rs;
- if (v1 < 0)
- v[1] = -v1;
-
- /* The case of a one digit divisor is treated specially. Not only
- * is this more efficient, but the general algorithm assumes that
- * the divisor contains at least two digits.
- */
-
- if (v[0] == 1) {
- q = int_new(u[0]);
-
- /* Basically this case is straight-forward. Since we can represent
- * numbers up to BAS * BAS - 1, we can do the steps of the division
- * exactly without any need for guess work. The division is then
- * done left to right(essentially it is the short division case).
- */
- rr = 0;
- for (j = 1; j <= u[0]; j++) {
- du = rr * BAS + u[j];
- q[j] = du / v[1];
- rr = du % v[1];
- }
-
- r = int_con(rr);
- }
- /* Here is where we must do the full long division algorithm */
-
- else {
- n = v[0];
- m = u[0] - v[0];
- q = int_new(m+1);
- t = int_new(u[0] + 1); /* extend u */
- for (j = 1; j <= u[0]; j++)
- t[j + 1] = u[j];
- int_free(u);
- u = t;
-
- /* The first step is to multiply both the divisor and dividend
- * by a scale factor. Obviously such scaling does not affect
- * the quotient. The purpose of this scaling is to ensure that
- * the first digit of the divisor is at least BAS / 2. This
- * condition is required for proper operation of the quotient
- * estimation algorithm used in the division loop. Note that
- * we added an extra digit at the front of the dividend above.
- */
-
- d = BAS /(v[1] + 1);
-
- c = 0;
- for (j = u[0]; j > 0; j--) {
- p = u[j] * d + c;
- u[j] = p % BAS;
- c = p / BAS;
- }
-
- c = 0;
- for (j = v[0]; j > 0; j--) {
- p = v[j] * d + c;
- v[j] = p % BAS;
- c = p / BAS;
- }
-
- /* This is the major loop, corresponding to long division steps */
-
- for (j = 1; j <= (m + 1); j++) {
- /* Guess the next quotient digit by doing a division based on the
- * leading digits. This estimate is never low and at most 2 high.
- */
- qe =(u[j] != v[1])
- ?((u[j] * BAS + u[j + 1]) / v[1])
- :(BAS - 1);
-
- /* The following loop refines this guess so that it is almost always
- * correct and is at worst one too high(see Knuth for proofs).
- */
-
- while((v[2] * qe) >
- ((u[j] * BAS + u[j + 1] - qe * v[1]) * BAS + u[j + 2])) {
- qe -= 1;
- }
-
- /* Now(for the moment accepting the estimate as correct), we
- * subtract the appropriate multiple of the divisor. This is
- * similar to the inner loop of the multiplication routine.
- */
- c = 0;
- for (k = n; k > 0; k--) {
- du = u[j + k] - qe * v[k] + c;
- u[j + k] = du % BAS;
- c = du / BAS;
- if (u[j + k] < 0) {
- u[j + k] += BAS;
- c -= 1;
- }
- }
- u[j] += c;
-
- /* If the estimate was one off, then u(j) went negative when the
- * final carry was added above. In this case, we add back the
- * divisor once, and adjust the quotient digit.
- */
-
- if (u[j] < 0) {
- qe -= 1;
-
- c = 0;
- for (k = n; k > 0; k--) {
- u[j + k] += v[k] + c;
- if (u[j + k] >= BAS) {
- u[j + k] -= BAS;
- c = 1;
- }
- else
- c = 0;
- }
-
- u[j] += c;
- }
-
- /* Store the next quotient digit */
-
- q[j] = qe;
- }
-
- /* Remainder is in u(m+2..m+n+1) but must be divided by d. */
-
-
- /* SETL: r:=int_quo(u(m+2..m+n+1), [d]); */
- t = int_new(n);
- ti = 1;
- for (i = m + 2; i <= (m + n + 1); i++)
- t[ti++] = u[i];
- r = int_quo(t, tt=int_con(d));
- int_free(t);
- int_free(tt);
- }
-
- /* All done, except for normalizing the quotient
- * to remove leading zeroes and supplying the
- * proper result sign to the returned values.
- */
-
- q = int__norm(q);
- if (qs < 0)
- q[1] = -q[1];
- if (rs < 0)
- r[1] = -r[1];
- *qa = q;
- *ra = r;
-
- int_free(u);
- int_free(v);
- }
-
- static int *int__addu(int *u, int *v) /*;int__addu*/
- {
- /* Add unsigned integers, cf Knuth 4.3.1 Algorithm A
- *
- * We first do the addition just to see if final carry, so we
- * can determine correct length of result. Then we allocate
- * the result and perform the addition.
- */
-
- int k = 0; /* carry */
- int *w;
- int r;
- int ui, vi, wi;
-
- /* Adjust so u points to longer argument */
-
- if (v[0] > u[0]) { /* if second longer */
- w = u;
- u = v;
- v = w;
- }
- ui = u[0]; /* length of first argument */
- vi = v[0];
- while(vi) {
- r = u[ui--] + v[vi--] + k;
- if (r >= BAS)
- k = 1;
- if (r < BAS)
- k = 0;
- }
- while(ui) {
- r = u[ui--] + k;
- if (r >= BAS)
- k = 1;
- if (r < BAS)
- k = 0;
- }
- /* if k nonzero, result needs extra component */
- w = int_new(u[0] + k);
- /* Now perform addition for real */
-
- /* Now we perform the addition from right to left in the familiar
- * paper and pencil manner. The variable k is the carry from the
- * previous column, which has either the value zero or one.
- */
-
- ui = u[0];
- vi = v[0];
- wi = w[0];
- k = 0;
- while(vi) {
- w[wi] = u[ui--] + v[vi--] + k;
- if (w[wi] >= BAS) {
- w[wi] -= BAS;
- k = 1;
- }
- else
- k = 0;
- wi--;
- }
- /* Now add in remainder of longer number */
- while(ui) {
- w[wi] += u[ui--] + k;
- if (w[wi] >= BAS) {
- w[wi] -= BAS;
- k = 1;
- }
- else
- k = 0;
- wi--;
- }
- if (k)
- w[1] = 1; /* if final carry */
-
- return w;
- }
-
- /* Note that int__norm does not alter its argument, but returns
- * pointer to(possibly normalized) multi-precision integer.
- */
- static int *int__norm(int *u) /*;int__norm*/
- {
- /* Remove leading zeroes from calculated value
- *
- * The representation used in this package requires that all integer
- * values be normalized, i.e. the first digit of any stored value
- * must be non-zero except for the special case of zero itself. The
- * normalize routine is called to ensure this condition is met.
- *
- */
-
- int i, j, *v;
-
- if (u[0] == 1 || u[1] != 0)
- return (u);
-
- for (i = 2; i <= u[0]; i++) {
- if (u[i]) {
- v = int_new(u[0] -(i - 1));
- for (j = 1; j <= v[0]; j++) {
- v[j] = u[i++];
- }
- int_free(u);
- return (v);
- }
- }
- /* Return zero if all components zero */
- return int_con(0);
- }
-
- /* Not used */
- int value(char *s) /*;value*/
- {
- /* Convert a numeric string to an integer. */
- return atoi(s);
- }
-
- static int *int_new(int n) /*;int_new*/
- {
- /* Allocate new integer with n components, each initially zero */
- int *p;
- int i;
-
- p =(int *) ecalloct((unsigned) n + 1, sizeof(int), "int-new");
- p[0] = n;
- for (i = 1; i <= n; i++)
- p[i] = 0;
- return p;
- }
-
- static void int_free(int *n) /*;int_free*/
- {
- efreet((char *) n, "int-free");
- }
-
- int *int_con(int i) /*;int_con*/
- {
- /* Build multi-precision integer from standard (short) integer */
- int *p;
-
- if (i<-BAS || i > BAS) chaos("int_con arg out of range ");
-
- p = int_new(1);
- p[1] = i;
- return p;
- }
-
- int *int_copy(int *u) /*;int_copy*/
- {
- /* Return copy of multi-precision integer u */
- int *p;
- int n, i;
-
- p = int_new(n = u[0]);
- for (i = 1; i <= n; i++)
- p[i] = u[i];
-
- return p;
- }
-
- int int_eqz(int *u) /*;int_eqz*/
- {
- /* Compare multi-precision integer with zero */
-
- int i;
-
- for (i = 1; i <= u[0]; i++)
- if (u[i]) return (FALSE);
- return TRUE;
- }
-
- int int_nez(int *u) /*;int_nez*/
- {
- /* Compare multi-precision integer with zero; true if not zero */
- return ! int_eqz(u);
- }
-
- /* end module ada - arith */
-
- #ifdef DEBUG
- /* debugging and test procedures */
- void int_print(int *u) /*;int_print*/
- {
- /* Dump multi-precision integer to standard output */
- int i, n;
- n = u[0];
- if (n <= 0) {
- chaos("ill-formatted arbitrary precision integer - lengt <= 0");
- }
- printf("integer: %d components\n", u[0]);
- printf("%3d %*d\n", 1, DIGS+1, u[1]); /* allow for possible sign */
- for (i = 2; i <= u[0]; i++)
- printf("%3d %0*d\n", i, DIGS, u[i]);
- }
- #endif
-
- /* module ada - arith */
- /*
- * All integers are stored in the multiple precision form used
- * in the package which is included as part of this program,
- * and rationals are stored as a pair [numerator, denominator],
- * with the denominator always positive, and [0] stored as [[0], n].
- * A rational plus or minus infinity may be represnted as
- * [n, [0]] or [-n, [0]] respectively. A rational of the form [[0], [0]]
- * will have an undefined effect if used in an operation.
- */
-
- /* Macros for access to rational numbers: */
-
- #define num(x) x->rnum
- #define den(x) x->rden
-
- Rational RAT_TWO;
- Rational ADA_MAX_FLOAT;
-
- /*
- * R A T I O N A L A R I T H M E T I C P A C K A G E
-
- * Robert B. K. Dewar
- * June 18th, 1980
-
- * This package contains a set of routines for performing
- * rational multiple precision arithmetic.
-
- *
- * A rational number is represented as a struct with two components, rnum
- * and rden, where num is the numerator, which may be negative, and den is
- * the denominator, which is non-zero and positive. Usually rational
- * numbers are reduced to lowest terms(see procedure rat_red), but none of
- * the routines depend on this assumption. The numerator and denominator
- * are represented as multiple precision integers, using the standard
- * formats for the multiple precision integer package, which must be
- * included as part of the program.
- * The macros num() and den() are used often, for comparison with the
- * original SETL code.
- *
- * The following routines are provided in the package
-
- * rat_abs rational absolute value
- * rat_add rational addition
- * rat_div rational division
- * rat_eql rational equal to
- * rat_exp raise rational to multiple precision integer power
- * rat_fri convert multiple precision integers to rational
- * rat_frr convert real to rational
- * rat_frs convert rational from string
- * rat_geq rational greater than or equal to
- * rat_gtr rational greater than
- * rat_leq rational less than or equal to
- * rat_lss rational less than
- * rat_mul rational multiplication
- * rat_neq rational not equal to
- * rat_rec rational reciprocal
- * rat_red reduce rational to lowest terms
- * rat_str convert integral fraction to string fraction
- * rat_sub rational subtraction
- * rat_tor convert rational to real
- * rat_toi convert rational to integer(rounds)
- * rat_tos convert rational to string
- * rat_tup convert string fraction to integral fraction
- * rat_umin rational unary minus
- */
-
- /*
- * The following procedures are introduced in the translation to C:
- * rat_new allocate new rational, set components
- * rat_free free rational(deallocate space, including
- * space used by components
- */
-
- void rat_init() /*;rat_init*/
- {
- /* Initialize rational and multi-precision packages */
-
- extern Rational RAT_TWO;
- extern Rational ADA_MAX_FLOAT;
-
- RAT_TWO = rat_new(int_con(2), int_con(1));
-
- /* ADA_MAX_FLOAT =
- * [[79, 228, 162, 514, 264, 337, 593, 543, 950, 336], [1]],
- * $ rational form of MAX_FLOAT
- * ADA_MAX_INTEGER_MP= [1, 073, 741, 823],
- * $ long form of ADA_MAX_INTEGER
- */
- /* Some C compilers do not like to see the most negative integer as
- * a constant, so we initialize ADA_MIN_INTEGER here by assingment
- * (assuming they can subtract properly!)
- */
- ADA_MAX_INTEGER = MAX_INTEGER; /* to be sure */
- ADA_MIN_INTEGER = -ADA_MAX_INTEGER;
- ADA_MIN_INTEGER--;
- ADA_MAX_INTEGER_MP = int_fri(ADA_MAX_INTEGER);
- ADA_MIN_INTEGER_MP = int_sub(int_umin(ADA_MAX_INTEGER_MP), int_fri(1));
- #ifdef MAX_INTEGER_LONG
- MIN_INTEGER_LONG = - MAX_INTEGER_LONG;
- MIN_INTEGER_LONG--;
- MAX_INTEGER_LONG_MP = int_frs(MAX_INTEGER_LONG_STRING);
- MIN_INTEGER_LONG_MP = int_sub(int_umin(MAX_INTEGER_LONG_MP),
- int_fri(1));
- ADA_MIN_FIXED = MIN_INTEGER_LONG;
- ADA_MAX_FIXED = MAX_INTEGER_LONG;
- MAX_INTEGER_LONG_MP = int_frs(MAX_INTEGER_LONG_STRING);
- MIN_INTEGER_LONG_MP = int_sub(int_umin(MAX_INTEGER_LONG_MP),
- int_fri(1));
- ADA_MIN_FIXED_MP = MIN_INTEGER_LONG_MP;
- ADA_MAX_FIXED_MP = MAX_INTEGER_LONG_MP;
- #endif
- #ifndef MAX_INTEGER_LONG
- ADA_MIN_FIXED = ADA_MIN_INTEGER;
- ADA_MAX_FIXED = ADA_MAX_INTEGER;
- ADA_MIN_FIXED_MP = ADA_MIN_INTEGER_MP;
- ADA_MAX_FIXED_MP = ADA_MAX_INTEGER_MP;
- #endif
- ADA_MAX_FLOAT = rat_new(
- int_frs("79228162514264337593543950336"),
- int_con(1));
- }
-
- Rational rat_new(int *u, int *v) /*;rat_new*/
- {
- Rational r;
-
- r =(Rational) emalloct(sizeof(Rational_s), "rat-new");
- r -> rnum = u;
- r -> rden = v;
- return r;
- }
-
- static void rat_free(Rational r) /*;rat_free*/
- {
- if (r->rnum != (int *)0) efreet((char *) r->rnum, "rat-free-num");
- if (r->rden != (int *)0) efreet((char *) r->rden, "rat-free-den");
- efreet((char *) r, "rat-free-rat");
- }
-
- #ifdef DEBUG
- void rat_print(Rational r) /*;rat_print*/
- {
- printf("rational \n");
- int_print(r -> rnum);
- int_print(r -> rden);
- }
- #endif
-
- Rational rat_abs(Rational u) /*;rat_abs*/
- {
- /* Absolute value of rational number */
-
- return rat_new(int_abs(num(u)), int_copy(den(u)));
- }
-
- Rational rat_add(Rational u, Rational v) /*;rat_add*/
- {
- /* Add rational numbers
- *
- * un vn un * vd + vn * ud
- * -- + -- = -------------------
- * ud vd ud * vd
- */
-
- int *rn, *rm, *tn, *tm;
-
- tn = int_mul(num(u), den(v));
- tm = int_mul(num(v), den(u));
- rn = int_add(tn, tm);
- rm = int_mul(den(u), den(v));
- int_free(tn);
- int_free(tm); /* free temporaries */
-
- return rat_new(rn, rm);
- }
-
-
- Rational rat_div(Rational u, Rational v) /*;rat_div*/
- {
- /*
- * Divide rational numbers
- *
- * un
- * --
- * ud
- * un * vd
- * ---- = -------
- * vn * ud
- * vn
- * --
- * vd
- *
- * Test for division by zero
- */
-
- int *rn, *rm;
-
- /* Return NULL instead of OM */
- if (int_eqz(num(v))) return ((Rational)0);
-
- /* Divisor is non-zero */
-
- else {
- rn = int_mul(num(u), den(v));
- rm = int_mul(num(v), den(u));
- /* if rm < 0 then
- * rn := -rn;
- * rm := abs rm;
- * end if;
- */
- if (rm[1] < 0) {
- rn[1] = -rn[1];
- rm[1] = -rm[1];
- }
-
- return rat_new(rn, rm);
- }
- }
-
- int rat_eql(Rational u, Rational v) /*;rat_eql*/
- {
- /* Test rational numbers for equality */
- int *rm, *rn, res;
-
- rn = int_mul(num(u), den(v));
- rm = int_mul(num(v), den(u));
- res = int_eql(rn, rm);
- int_free(rn);
- int_free(rm); /* free temporaries */
- return res;
- }
-
- Rational rat_exp(Rational u, int *ea) /*;rat_exp*/
- {
- /* Raise rational number to multiple precision integer power
- *
- * If e >= 0: If e < 0:
- *
- * un un ** e un 1 ud **(-e)
- * -- ** e = ------- -- ** e = --------------- = ----------
- * ud ud ** e ud (un/ud) **(-e) un **(-e)
- */
-
- int *e;
-
- if (int_eqz(num(u)))
- return int_eqz(ea) ? rat_new(int_con(1), int_con(1))
- : rat_new(int_con(0), int_con(1));
-
- e = int_copy(ea); /* preserve value semantics */
-
- if (e[1] < 0) {
- u = rat_rec(u);
- e[1] = -e[1];
- }
-
- return rat_new(int_exp(num(u), e), int_exp(den(u), e));
- }
-
- Rational rat_fri(int *u, int *v) /*;rat_fri*/
- {
- /* Convert multiple precision integers to a rational number. */
-
- return rat_new(int_copy(u), int_copy(v));
- }
-
- Rational rat_frr(double u) /*;rat_frr*/
- {
- /* Convert a SETL real to a rational number.
- *
- * converts a floating number u to a pair of integers [p, y] such that
- * u = 2.0**p * float y
- * Here y satisfies 2**(N-1) <= abs y < 2 ** N
- * where N is the number of mantissa bits.
- * This essentially separates the fraction and the exponent.
- */
- /* The present C version is a straightforward translation of the SETL
- * code. Still unanswered is the question of whether real values will
- * be represented in C using doubles or floats; for now we assume reals
- * as floats. A more efficient version using library function 'frexp'
- * may be possible.
- */
-
- int sgn;
- float ub, lb;
- int p, y;
- if (u == 0.0)
- return rat_new(int_con(0), int_con(1));
-
- if (u < 0) {
- u = -u;
- sgn = -1;
- }
- else {
- sgn = 1;
- }
- ub = pow2(ADA_MANTISSA_SIZE);
- lb = pow2(ADA_MANTISSA_SIZE - 1);
-
- p =(int)(log((double) u) / log((double) 2.0)) - ADA_MANTISSA_SIZE;
- /* estimate the exponent */
- u = u * pow2(-p);
- /* and adjust number */
- while(u >= ub) {
- u /= 2.0; /* scale down */
- p += 1;
- }
- while(u < lb) {
- u *= 2.0; /* scale up; */
- p -= 1;
- }
- y = sgn *(int) u;
- return rat_mul(rat_exp(RAT_TWO, int_fri(p)),
- rat_new(int_fri(y), int_con(1)));
- }
-
- /* Not used */
- Rational rat_frs(char *s) /*;rat_frs*/
- {
- /* Convert a string representing a decimal fraction to the corresponding
- * rational number. The string consists of a digit string, optionally
- * containing a decimal point and preceded by an optional sign. If an
- * erroneous string is passed as an argument, then OM is returned.
- *
- * First step is to find number of digits after decimal point
- */
-
- int dp, n, frac;
- int *i;
- char *t;
-
- n = strlen(s);
-
- t = strrchr(s, '.');
- frac =(t == (char *)0) ? 0 :(t - s + 1);
- /* find position of decimal point */
- dp = 0;
- if (frac != 0) {
- dp = n - frac;
- t = emalloct((unsigned) n, "rat-frs");
- *t = '\0'; /* mark end of(initially) null string */
- if (frac > 1)
- strncat(t, s, frac - 1);
- strncat(t, s + frac, (n - frac));
- }
- else
- t = s;
- /* Then number is converted as integer, and result is obtained
- * by supplying the appropriate power of ten as the denominator.
- */
-
- i = int_frs(t);
-
- #ifdef XDEFER
- /* defer this while putting salloc in place DS (2-22-86) */
- if (frac)
- efreet(t, "rat-frs"); /* return t if allocated here */
- #endif
-
- if (i == (int *)0)
- return (Rational)0;
- else
- return rat_red(i, int_ptn(dp));
- }
-
- int rat_geq(Rational u, Rational v) /*;rat_geq*/
- {
- /* Compare rational numbers: return true if u >= v, false otherwise. */
-
- return ! rat_lss(u, v);
- }
-
- int rat_gtr(Rational u, Rational v) /*;rat_gtr*/
- {
- /* Compare rational numbers: return true if u > v, false otherwise. */
-
- return (rat_eql(u, v) ? 0 : rat_lss(v, u));
- }
-
- int rat_leq(Rational u, Rational v) /*;rat_leq*/
- {
- /* Compare rational numbers: return true if u <= v, false otherwise. */
-
- return (rat_eql(u, v) ? 1 : rat_lss(u, v));
- }
-
- int rat_lss(Rational u, Rational v) /*;rat_lss*/
- {
- /* Compare rational numbers: return true if u < v, false otherwise.
- *
- * un vn
- * -- < -- iff un * vd < vn * ud
- * ud vd
- */
- int *rn, *rd, res;
- rn = int_mul(num(u), den(v));
- rd = int_mul(num(v), den(u));
- res = int_lss(rn, rd);
- int_free(rn);
- int_free(rd);
- return res;
- }
-
- Rational rat_mul(Rational u, Rational v) /*;rat_mul*/
- {
- /*
- * Multiply rational numbers
- *
- * un vn un * vn
- * -- * -- = -------
- * ud vd ud * vd
- */
-
- int *rn, *rm;
-
- rn = int_mul(num(u), num(v));
- rm = int_mul(den(u), den(v));
-
- return rat_red(rn, rm);
- }
-
- int rat_neq(Rational u, Rational v) /*;rat_neq*/
- {
- /* Test rational numbers for inequality */
-
- return ! rat_eql(u, v);
- }
-
- Rational rat_rec(Rational u) /*;rat_rec*/
- {
- /* Find reciprocal of rational number(number should not be zero). */
-
- int *un, *dn;
-
- un = int_copy(den(u));
- dn = int_copy(num(u));
- if (dn[1] < 0) {
- un[1] = -un[1];
- dn[1] = -dn[1];
- }
- return rat_new(un, dn);
- }
-
- Rational rat_red(int *un, int *ud) /*;rat_red*/
- {
- /* Form rational reduced to lowest terms
- *
- * This procedure is given as arguments the numerator and denominator
- * of a rational value(as multiple precision integers). It returns
- * the rational formed by reducing these values to lowest terms.
- *
- * First a special case: zero is reduced to [[0], [1]] .
- */
-
- int *i, *j, *t, *gcd, usign, dsign, rsign;
-
- if (int_eqz(un)) {
- return rat_new(int_con(0), int_con(1));
-
- /* Another special case: plus or minus infinity is reduced to [[1], [0]]
- * or [[-1], [0]] .
- */
- }
- else {
- if (int_eqz(ud)) {
- return rat_new(int_con((un[1] < 0 ? -1 :((un)[1] > 0 ? 1 : 0))),
- int_con(0));
- }
- /* Else we must compute GCD, using Euclid's algorithm. */
-
- else {
- usign = SIGN(un[1]);
- dsign = SIGN(ud[1]);
- rsign = usign == dsign ? 1 : -1;
- i = int_copy(un);
- i[1] = i[1] >= 0 ? i[1] : -i[1];
- j = int_copy(ud);
- j[1] = j[1] >= 0 ? j[1] : -j[1];
- if (int_gtr(j, i)) {
- t = i;
- i = j;
- j = t;
- }
- /* Steps of Euclid's algorithm, at each step, i is greater than
- * or equal to j, i is replaced by j and j is replaced by the
- * remainder of dividing i by j. The algorithm terminates when
- * j is zero, with i being the greatest common divisor.
- */
-
- while(int_nez(j)) {
- t = j;
- j = int_rem(i, j);
- i = t;
- /* [i, j] := [j, int_rem(i, j)]; */
- }
-
- gcd = i;
-
- /* Now reduce the original to lowest terms using the computed GCD */
-
- i = int_quo(un, gcd);
- j = int_quo(ud, gcd);
- /* adjust signs if needed */
- if (i[1] < 0) i[1] = -i[1];
- if (j[1] < 0) j[1] = -j[1];
- if (rsign < 0) i[1] = -i[1];
- return rat_new(i, j);
-
- }
- }
- }
-
- #ifdef TBSN
- char **rat_str(int **q) /*;rat_str*/
- {
- /* Convert tuple of multiple precision integers to tuple of
- * strings.
- * We interpret the argument q as a pointer to an array of pointers
- * to multi-precision integers.
- */
-
- char *emalloct();
- char *p;
-
- p = ecalloct(2, sizeof(char *), "rat-str");
- p[0] = int_tos(*q[0]);
- p[1] = int_tos(*q[1]);
- return &p;
- }
- #endif
-
- Rational rat_sub(Rational u, Rational v) /*;rat_sub*/
- {
- /* Subtract rational numbers
- *
- * un vn un * vd - vn * ud
- * -- - -- = -------------------
- * ud vd ud * vd
- */
-
- int *rn, *rm, *tn, *tm;
-
- tn = int_mul(num(u), den(v));
- tm = int_mul(num(v), den(u));
- rn = int_sub(tn, tm);
- int_free(tn);
- int_free(tm);
- rm = int_mul(den(u), den(v));
- return rat_new(rn, rm);
- }
-
- double rat_tor (Rational u, int n) /*;rat_tor*/
- {
- /* TBSL: need to review and test this code ds 11 sep 84 */
- double real1;
- int sgn, numpow, denpow;
- int *nu, *du;
- int *ub, *lb, p, *lbnd;
- int *iquo;
- long ntmp;
- double log_bas, rpow, res;
- /* Convert a multiple precision real to a SETL real, if possible.
- * Make copy and work with positives
- */
- u = rat_red(num(u), den(u));
- arith_overflow = 0;
- nu = num(u);
- sgn = SIGN(nu[1]);
- nu[1] = ABS(nu[1]);
-
- /* Check for 0 */
-
- if (sgn == 0 ) {
- rat_free(u);
- return 0.0;
- }
-
- /* Check for overflow */
-
- if (rat_gtr(u, ADA_MAX_FLOAT)) {
- arith_overflow = 1;
- return 0.0;
- }
-
- /* To find an accurate floating representation of a rational number,
- * we normalize it so that
- *
- * 2 ** (N - 1) <= (num/den) < 2 ** N
- *
- * where N is the size of the mantissa.
- * We can then perform a long division, and know that the mantissa is
- * accurate to 2 ** (-N) i.e. to the last bit.
- */
- real1 = BAS;
- log_bas = log(real1) / log(2.0);
- ub = int_frl((long) pow2(ADA_MANTISSA_SIZE));
- lb = int_frl((long) pow2(ADA_MANTISSA_SIZE - 1));
-
- nu = num(u);
- du = den(u);
- numpow = (int)((double)((nu[0]-1)) * log_bas + log((double)nu[1])/log(2.0));
- denpow = (int)((double)((du[0]-1)) * log_bas + log((double)du[1])/log(2.0));
-
- p = numpow - denpow - ADA_MANTISSA_SIZE;
- if (p < 0 ) { /* -p > 0 */
- nu = int_mul(nu, int_exp(int_fri(2), int_fri(-p)));
- }
- else { /* p >= 0 */
- du = int_mul(du, int_exp(int_fri(2), int_fri(p)));
- }
-
- while (int_geq(nu, int_mul(ub, du))) {
- du = int_add(du, du);
- p++;
- }
- lbnd = int_mul(lb, du);
- while (int_lss(nu, lbnd)) {
- nu = int_add(nu, nu);
- p--;
- }
- iquo = int_quo(nu, du);
- ntmp = int_tol(iquo);
- real1 = sgn * ntmp;
- rpow = pow2(p);
- res = real1 * rpow;
- return res;
- }
-
- int rat_toi(Rational u) /*;rat_toi*/
- {
- /* Convert the rational number u to a SETL integer. The number
- * u is rounded by adding rational 1/2 or -1/2. The int_quo
- * procedure is used to obtain the result of dividing the
- * numerator by the denominator. The resuling extended integer is
- * then converted to a SETL integer using int_toi.
- */
-
- int t, s;
- Rational r;
-
- t = num(u)[1];
- s = t == 0 ? 0 : t > 0 ? 1 : -1;/* get sign of u */
- /* s := sign num(u)(1); $ get sign of u */
- /* add or subtract 1/2(or 0) */
- r = rat_add(u, rat_new(int_con(s), int_con(2)));
- return int_toi(int_quo(num(r), den(r)));
- /* get quotient and convert it */
- }
-
- long rat_tol(Rational u) /*;rat_tol*/
- {
- /* Convert the rational number u to a (long)integer. The number
- * u is rounded by adding rational 1/2 or -1/2. The int_quo
- * procedure is used to obtain the result of dividing the
- * numerator by the denominator. The resuling extended integer is
- * then converted to a SETL integer using int_toi.
- */
-
- int t, s;
- Rational r;
-
- t = num(u)[1];
- s = t == 0 ? 0 : t > 0 ? 1 : -1;/* get sign of u */
- /* s := sign num(u)(1); $ get sign of u */
- /* add or subtract 1/2(or 0) */
- r = rat_add(u, rat_new(int_con(s), int_con(2)));
- return int_tol(int_quo(num(r), den(r)));
- /* get quotient and convert it */
- }
-
- #ifdef TBSN
- proc rat_tos (u, n); /*;rat_tos*/
-
- /*
- * Convert a rational number u to a decimal
- * string with n places after the decimal point. The result
- * is correctly rounded and always has the specified number
- * of digits after the decimal place (even if they are zero)
- *
- * First acquire the sign (and then work with positive numbers)
- */
-
- int *q, *r;
-
- sn :
- = '';
- if num(u)(1) < 0 then
- num(u)(1) :
- = abs num(u)(1);
- sn :
- = '-';
- end if;
-
- /*
- * Form result by multiplying by power of ten corresponding
- * to number of decimal places and then doing division.
- */
-
- un :
- = int_mul (num(u), int_ptn (n));
- ud :
- = den(u);
- int_div(un, ud, &q, &r);
- if int_gtr (int_mul (r, [2]), ud) then
- q:
- =int_add(q, [1]);
- end if;
-
- /*
- * Return result by converting this integer to a string and
- * then supplying the decimal point at the appropriate position.
- */
-
- q :
- = int_tos (q);
- if #q <= n then
- q :
- = (n + 1 - #q) * '0' + q;
- end if;
-
- return sn + q(1..#q-n) + '.' + q(#q-n+1..);
-
- end proc rat_tos;
- #endif
-
- #ifdef TBSN
- Rational *rat_tup(char **q) /*;rat_tup*/
- {
- /* Convert tuple of strings to tuple of multiple precision integers.
- * We interpret tuple of strings as pointer to array of pointers to
- * strings.
- */
-
- char *ecalloct();
- Rational *p;
-
- p = ecalloct(2, sizeof(Rational ), "rat-tup");
-
- p[0] = int_frs(*q[0]);
- p[1] = int_frs(*q[1]);
- return &p;
- }
- #endif
-
- Rational rat_umin(Rational u) /*;rat_umin*/
- {
- /* Rational unary minus */
-
- return rat_new(int_umin(num(u)), int_copy(den(u)));
- }
-
- static double pow2(int p) /*;pow2*/
- {
- double running, result;
-
- result = 1.0;
-
- if (p < 0) {
- running = 0.5;
- p = -p;
- }
- else {
- running = 2.0;
- }
-
- while(p != 0) {
-
- /* If p is odd then multiply result by running. */
-
- if (p % 2 == 1)
- result = result * running;
-
- /* Square running. */
-
- running = running * running;
-
- p /= 2;
- }
-
- return result;
- }
-